﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WPFModel.BusinessModelObject;
using System.Reflection;
using System.ComponentModel;
using WPFModel;

namespace WPFApplication.Controls
{
    /// <summary>
    /// Interaction logic for UCProperties.xaml
    /// </summary>
    public partial class UCProperties : UserControl
    {
        #region Properties
        BaseModel baseModel
        {
            get;
            set;
        }
        BaseField baseField
        {
            get;
            set;
        }
        #endregion

        #region Constructor
        public UCProperties()
        {
            InitializeComponent();
        }
        #endregion

        #region Methods
        void createRow<T>(T obj, PropertyInfo p)
        {
            // Insertando un row definition
            RowDefinition rd = new RowDefinition { Height = new GridLength(30) };
            gridProperty.RowDefinitions.Add(rd);

            // Obteniendo la descripción de la propiedad del objeto
            string description = getAttributes<DescriptionAttribute>(p).Description;
            createLabel(description);
            createControl<T>(obj, p);
        }
        void createLabel(string label)
        {
            TextBlock txb = new TextBlock();
            txb.Text = label;
            Grid.SetRow(txb, gridProperty.RowDefinitions.Count - 1);
            Grid.SetColumn(txb, 0);

            gridProperty.Children.Add(txb);
        }
        void createControl<T>(T obj, PropertyInfo p)
        {
            TypePropertyAttribute tp = getAttributes<TypePropertyAttribute>(p);
            if (tp == null) return;

            switch (tp.Control)
            {
                case TypeControl.ComboBoxContol: createComboBox<T>(obj, p); break;
                case TypeControl.TextBoxControl: createTextBox<T>(obj, p); break;
                case TypeControl.TextAndListControl: createTextAndList<T>(obj, p); break;
            }
        }

        #region Create Controls
        void createComboBox<T>(T obj, PropertyInfo p)
        {
            if (!p.PropertyType.IsEnum) return;

            ComboBox cbo = new ComboBox();
            cbo.Tag = p.Name;
            cbo.SelectionChanged += new SelectionChangedEventHandler(lst_SelectionChanged);

            string selectedText = p.GetValue(obj, null).ToString();

            foreach (string s in Enum.GetNames(p.PropertyType))
            {
                ComboBoxItem item = new ComboBoxItem { Content = s };
                cbo.Items.Add(item);

                if (string.Equals(s, selectedText, StringComparison.OrdinalIgnoreCase))
                    cbo.SelectedItem = item;
            }

            Grid.SetRow(cbo, gridProperty.RowDefinitions.Count - 1);
            Grid.SetColumn(cbo, 1);

            gridProperty.Children.Add(cbo);
        }
        void createTextBox<T>(T obj, PropertyInfo p)
        {
            TextBox txt = new TextBox();
            txt.Tag = p.Name;
            txt.TextChanged += new TextChangedEventHandler(txt_TextChanged);
            txt.Text = p.GetValue(obj, null).ToString();

            Grid.SetRow(txt, gridProperty.RowDefinitions.Count - 1);
            Grid.SetColumn(txt, 1);

            gridProperty.Children.Add(txt);
        }
        void createTextAndList<T>(T obj, PropertyInfo p)
        {
            ComboBox cbo = new ComboBox();
            TextBox txt1 = new TextBox();
            TextBox txt2 = new TextBox();

            Grid gridControl = new Grid();
            gridControl.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
            gridControl.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
            gridControl.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
            gridControl.RowDefinitions.Add(new RowDefinition());

            Grid.SetRow(cbo, 0);
            Grid.SetColumn(cbo, 0);
            Grid.SetRow(txt1, 0);
            Grid.SetColumn(txt1, 1);
            Grid.SetRow(txt2, 0);
            Grid.SetColumn(txt2, 2);
            gridControl.Children.Add(cbo);
            gridControl.Children.Add(txt1);
            gridControl.Children.Add(txt2);


            Grid.SetRow(gridControl, gridProperty.RowDefinitions.Count - 1);
            Grid.SetColumn(gridControl, 1);

            gridProperty.Children.Add(gridControl);
        }

        void lst_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox cbo = (ComboBox)sender;
            if (string.IsNullOrEmpty(cbo.Text)) return;

            object obj = (baseField != null) ? (object)baseField : (object)baseModel;

            PropertyInfo pi = obj.GetType().GetProperty(cbo.Tag.ToString());
            object newEnumValue = Enum.Parse(pi.PropertyType, ((ComboBoxItem)cbo.SelectedItem).Content.ToString());
            pi.SetValue(obj, newEnumValue, null);

        }
        void txt_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox txt = (TextBox)sender;
            if (string.IsNullOrEmpty(txt.Text)) return;

            object obj = (baseField != null) ? (object)baseField : (object)baseModel;

            PropertyInfo pi = obj.GetType().GetProperty(txt.Tag.ToString());
            pi.SetValue(obj, txt.Text, null);
        }
        #endregion


        public void ShowProperties<T>(T model)
        {
            baseModel = model as BaseModel;
            baseField = default(BaseField);
            PropertyInfo[] properties = model.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
                createRow<T>(model, property);
        }
        public void ShowProperties<T, K>(T model, K p)
        {
            baseModel = model as BaseModel;
            baseField = p as BaseField;
            PropertyInfo[] properties = p.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
                createRow<K>(p, property);
        }
        public T GetObject<T>()
        {
            object obj = (baseField != null) ? (object)baseField : (object)baseModel;
            return (T)obj;
        }
        #endregion

        #region Utils
        T getAttributes<T>(PropertyInfo p)
        {
            object[] attrs = p.GetCustomAttributes(typeof(T), true);
            if (attrs.Length > 0)
                return (T)attrs[0];

            return default(T);
        }
        #endregion
    }
}
